#include "Crate.h"


Crate::Crate(D3DXVECTOR3* eyePos,D3DXMATRIX* matView,D3DXMATRIX* proj)
	:m_iNumVertices(0)
	,m_iNumFaces(0)
	,m_pDevice(NULL)
	,m_pVB(NULL)
	,m_pIB(NULL)
	,m_pFx(NULL)
	,m_pInputLayout(NULL)
	,m_pFxTech(NULL)
	,m_pFxDiffuseMapVar(NULL)
	,m_pFxSpecMapVar(NULL)
	,m_pFxWVPVar(NULL)
	,m_pFxWorldVar(NULL)
	,m_pFxTexMtxVar(NULL)
	,m_pFxEyePosVar(NULL)
	,m_pFxLightVar(NULL)
	,m_pEyePos(eyePos)
	,m_pMatProj(proj)
	,m_pMatView(matView)
{
	D3DXMatrixIdentity(&m_matWVP);
	D3DXMatrixIdentity(&m_matWorld);
	D3DXMatrixIdentity(&m_matTexMtx);
}


Crate::~Crate(void)
{
	ReleaseCOM(m_pIB);
	ReleaseCOM(m_pVB);

	ReleaseCOM(m_pFx);
	ReleaseCOM(m_pInputLayout);
	ReleaseCOM(m_pDiffuseMapRV);
	ReleaseCOM(m_pSpecMapRV);
}

void Crate::Init( ID3D10Device* device, float scale )
{
	m_pDevice = device;

	buildFX();
	buildVertexLayouts();

	//create the texture resource view
	HR( D3DX10CreateShaderResourceViewFromFile(m_pDevice,L"WoodCrate01.dds"
		,0,0,&m_pDiffuseMapRV,0) );

	HR( D3DX10CreateShaderResourceViewFromFile(m_pDevice,L"defaultspec.dds"
		,0,0,&m_pSpecMapRV,0) );

	m_iNumVertices = 24;
	m_iNumFaces    = 12; // 2 per quad

	// Create vertex buffer
	Vertex v[24];

	// Fill in the front face vertex data.
	v[0] = Vertex(-1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f);
	v[1] = Vertex(-1.0f,  1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f);
	v[2] = Vertex( 1.0f,  1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f);
	v[3] = Vertex( 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f);

	// Fill in the back face vertex data.
	v[4] = Vertex(-1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f);
	v[5] = Vertex( 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f);
	v[6] = Vertex( 1.0f,  1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f);
	v[7] = Vertex(-1.0f,  1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f);

	// Fill in the top face vertex data.
	v[8]  = Vertex(-1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f);
	v[9]  = Vertex(-1.0f, 1.0f,  1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f);
	v[10] = Vertex( 1.0f, 1.0f,  1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f);
	v[11] = Vertex( 1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f);

	// Fill in the bottom face vertex data.
	v[12] = Vertex(-1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f);
	v[13] = Vertex( 1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f);
	v[14] = Vertex( 1.0f, -1.0f,  1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f);
	v[15] = Vertex(-1.0f, -1.0f,  1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f);

	// Fill in the left face vertex data.
	v[16] = Vertex(-1.0f, -1.0f,  1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f);
	v[17] = Vertex(-1.0f,  1.0f,  1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f);
	v[18] = Vertex(-1.0f,  1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f);
	v[19] = Vertex(-1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f);

	// Fill in the right face vertex data.
	v[20] = Vertex( 1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f);
	v[21] = Vertex( 1.0f,  1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f);
	v[22] = Vertex( 1.0f,  1.0f,  1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f);
	v[23] = Vertex( 1.0f, -1.0f,  1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f);

	// Scale the box.
	for(DWORD i = 0; i < m_iNumVertices; ++i)
		v[i].pos *= scale;


	D3D10_BUFFER_DESC vbd;
	vbd.Usage = D3D10_USAGE_IMMUTABLE;
	vbd.ByteWidth = sizeof(Vertex) * m_iNumVertices;
	vbd.BindFlags = D3D10_BIND_VERTEX_BUFFER;
	vbd.CPUAccessFlags = 0;
	vbd.MiscFlags = 0;
	D3D10_SUBRESOURCE_DATA vinitData;
	vinitData.pSysMem = v;
	HR(m_pDevice->CreateBuffer(&vbd, &vinitData, &m_pVB));


	// Create the index buffer

	DWORD i[36];

	// Fill in the front face index data
	i[0] = 0; i[1] = 1; i[2] = 2;
	i[3] = 0; i[4] = 2; i[5] = 3;

	// Fill in the back face index data
	i[6] = 4; i[7]  = 5; i[8]  = 6;
	i[9] = 4; i[10] = 6; i[11] = 7;

	// Fill in the top face index data
	i[12] = 8; i[13] =  9; i[14] = 10;
	i[15] = 8; i[16] = 10; i[17] = 11;

	// Fill in the bottom face index data
	i[18] = 12; i[19] = 13; i[20] = 14;
	i[21] = 12; i[22] = 14; i[23] = 15;

	// Fill in the left face index data
	i[24] = 16; i[25] = 17; i[26] = 18;
	i[27] = 16; i[28] = 18; i[29] = 19;

	// Fill in the right face index data
	i[30] = 20; i[31] = 21; i[32] = 22;
	i[33] = 20; i[34] = 22; i[35] = 23;

	D3D10_BUFFER_DESC ibd;
	ibd.Usage = D3D10_USAGE_IMMUTABLE;
	ibd.ByteWidth = sizeof(DWORD) * m_iNumFaces*3;
	ibd.BindFlags = D3D10_BIND_INDEX_BUFFER;
	ibd.CPUAccessFlags = 0;
	ibd.MiscFlags = 0;
	D3D10_SUBRESOURCE_DATA iinitData;
	iinitData.pSysMem = i;
	HR(m_pDevice->CreateBuffer(&ibd, &iinitData, &m_pIB));

	//set the light
	m_ParallelLight.dir      = D3DXVECTOR3(0.57735f, -0.57735f, 0.57735f);
	m_ParallelLight.ambient  = D3DXCOLOR(0.4f, 0.4f, 0.4f, 1.0f);
	m_ParallelLight.diffuse  = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f);
	m_ParallelLight.specular = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f);
}

void Crate::Draw()
{
	UINT stride = sizeof(Vertex);
	UINT offset = 0;
	m_pDevice->OMSetDepthStencilState(0, 0);
	m_pDevice->IASetInputLayout(m_pInputLayout);
	m_pDevice->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

	m_pDevice->IASetVertexBuffers(0, 1, &m_pVB, &stride, &offset);
	m_pDevice->IASetIndexBuffer(m_pIB, DXGI_FORMAT_R32_UINT, 0);


	//update the fx variable
	m_pFxEyePosVar->SetRawValue(m_pEyePos, 0, sizeof(D3DXVECTOR3));
	m_pFxLightVar->SetRawValue(&m_ParallelLight, 0, sizeof(Light));
	m_matWVP = m_matWorld*(*m_pMatView)*(*m_pMatProj);
	m_pFxWVPVar->SetMatrix((float*)&m_matWVP);
	m_pFxWorldVar->SetMatrix((float*)&m_matWorld);
	m_pFxDiffuseMapVar->SetResource(m_pDiffuseMapRV);
	m_pFxSpecMapVar->SetResource(m_pSpecMapRV);

	m_pFxTexMtxVar->SetMatrix((float*)&m_matTexMtx);

	D3D10_TECHNIQUE_DESC techDesc;
	m_pFxTech->GetDesc(&techDesc);
	for(UINT p=0; p<techDesc.Passes; ++p)
	{
		m_pFxTech->GetPassByIndex(p)->Apply(0);

		m_pDevice->DrawIndexed(m_iNumFaces*3, 0, 0);
	}
}

void Crate::buildFX()
{
	DWORD shaderFlags = D3D10_SHADER_ENABLE_STRICTNESS;
#if defined( DEBUG ) || defined( _DEBUG )
	shaderFlags |= D3D10_SHADER_DEBUG;
	shaderFlags |= D3D10_SHADER_SKIP_OPTIMIZATION;
#endif

	ID3D10Blob* compilationErrors = 0;
	HRESULT hr = 0;
	hr = D3DX10CreateEffectFromFile(L"Crate.fx", 0, 0, 
		"fx_4_0", shaderFlags, 0, m_pDevice, 0, 0, &m_pFx, &compilationErrors, 0);
	if(FAILED(hr))
	{
		if( compilationErrors )
		{
			MessageBoxA(0, (char*)compilationErrors->GetBufferPointer(), 0, 0);
			ReleaseCOM(compilationErrors);
		}
		DXTrace(__FILE__, (DWORD)__LINE__, hr, L"D3DX10CreateEffectFromFile", true);
	} 

	m_pFxTech = m_pFx->GetTechniqueByName("CrateTech");

	m_pFxWVPVar        = m_pFx->GetVariableByName("gWVP")->AsMatrix();
	m_pFxWorldVar      = m_pFx->GetVariableByName("gWorld")->AsMatrix();
	m_pFxEyePosVar     = m_pFx->GetVariableByName("gEyePosW");
	m_pFxLightVar      = m_pFx->GetVariableByName("gLight");
	m_pFxDiffuseMapVar = m_pFx->GetVariableByName("gDiffuseMap")->AsShaderResource();
	m_pFxSpecMapVar    = m_pFx->GetVariableByName("gSpecMap")->AsShaderResource();
	m_pFxTexMtxVar     = m_pFx->GetVariableByName("gTexMtx")->AsMatrix();
}

void Crate::buildVertexLayouts()
{
	// Create the vertex input layout.
	D3D10_INPUT_ELEMENT_DESC vertexDesc[] =
	{
		{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0},
		{"NORMAL",   0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA, 0},
		{"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT,    0, 24, D3D10_INPUT_PER_VERTEX_DATA, 0},
	};

	// Create the input layout
	D3D10_PASS_DESC PassDesc;
	m_pFxTech->GetPassByIndex(0)->GetDesc(&PassDesc);
	HR(m_pDevice->CreateInputLayout(vertexDesc, 3, PassDesc.pIAInputSignature,
		PassDesc.IAInputSignatureSize, &m_pInputLayout));
}
